home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 526-550 / disk_535 / keymacro / ikm.c < prev    next >
Text File  |  1992-05-06  |  10KB  |  371 lines

  1. /**************************************************************************
  2. *
  3. *    ikm.c    - Olsen's magical key inversion routines.
  4. *
  5. *          You may use this piece of code in any application
  6. *          without requesting permission of the original author.
  7. *
  8. *          It is strongly recommended to use cx.lib/InvertString
  9. *          instead of the following set of routines when running
  10. *          under v37 or higher.
  11. *
  12. *          Basically, the following code is derived from the
  13. *          keymap inversion routines employed by KeyMacro 1.9,
  14. *          strange enough the german keymap would never be
  15. *          read correctly to generate the letter `f'. This and
  16. *          a lot of other problems have been fixed (keep your
  17. *          fingers crossed!) and single-depth-dead-key
  18. *          conversion was added on the fly (i.e. accented
  19. *          characters can be generated with keyboard layouts
  20. *          which do not contain accent keys).
  21. *
  22. *          Jimm Mackraz' original ikm.c code, Bill Hawes'
  23. *          cmap.asm example keymap, and the `International
  24. *          Keyboard Input' article by Eric Cotton and Carolyn
  25. *          Scheppner published in Amiga-Mail provided enough
  26. *          help to create the current release of this package
  27. *          (which also is significantly shorter than Jimm's
  28. *          original ikm.c code).
  29. *
  30. *          A potential problem still exists: what happens if
  31. *          a dead-key-modifiable key sports less than three
  32. *          qualifiers (shift, alternate, control)? The
  33. *          `International Keyboard Input' article states that
  34. *          the number of qualifiers determines the format and the
  35. *          length of the corresponding mk_Hi/LowKeyMap entry.
  36. *          Unfortunately, no word is lost on how a keymap entry
  37. *          of such kind would look like. For now my code
  38. *          determines the number of table entries to look up
  39. *          by counting the qualifiers listed in
  40. *          km_Hi/LowKeyMapTypes which will probably find the
  41. *          approriate key but will fail to generate a matching
  42. *          qualifier (do YOU know of a fix?).
  43. *
  44. *          Anyway, keymap inversion is a weird topic which
  45. *          had better been covered in the early days of
  46. *          the Amiga.
  47. *
  48. *          A note to code hackers:
  49. *
  50. *            Sometimes InvertKeyMap() will not return the
  51. *            proper raw key value for a character but
  52. *            rather the raw key value of the base character
  53. *            (example: character = á, base character = a).
  54. *            To avoid unpleasant sideeffects, just remove
  55. *            the dead key conversion in lines 214-225
  56. *            (delete the loop, only check the first character
  57. *            of the array).
  58. */
  59.  
  60.     /* PackQualifiers(BYTE Bits):
  61.      *
  62.      *    Piece together a valid pack of qualifiers from
  63.      *    a bitmapped key position.
  64.      */
  65.  
  66. STATIC UWORD
  67. PackQualifiers(BYTE Bits)
  68. {
  69.     UWORD Qualifier = 0;
  70.  
  71.     if(Bits & KCF_SHIFT)
  72.         Qualifier |= IEQUALIFIER_LSHIFT;
  73.  
  74.     if(Bits & KCF_ALT)
  75.         Qualifier |= IEQUALIFIER_LALT;
  76.  
  77.     if(Bits & KCF_CONTROL)
  78.         Qualifier |= IEQUALIFIER_CONTROL;
  79.  
  80.     return(Qualifier);
  81. }
  82.  
  83.     /* CountPairs(BYTE Qualifiers):
  84.      *
  85.      *    Count the number (not the one from Sesame Street) of
  86.      *    qualifiers given in a KeyMapTypes entry.
  87.      */
  88.  
  89. STATIC BYTE
  90. CountPairs(BYTE Qualifiers)
  91. {
  92.     BYTE Bits = 1;
  93.  
  94.     if(Qualifiers & KCF_SHIFT)
  95.         Bits++;
  96.  
  97.     if(Qualifiers & KCF_ALT)
  98.         Bits++;
  99.  
  100.     if(Qualifiers & KCF_CONTROL)
  101.         Bits++;
  102.  
  103.     return(Bits);
  104. }
  105.  
  106.     /* FindIndexKey():
  107.      *
  108.      *    Find the key which if `preceding' the inverted base key
  109.      *    will generate the accented character (example: character
  110.      *    to be inverted = á, inverted base key = a, the preceding
  111.      *    key we are trying to find in this routine will put the
  112.      *    accent ´ on top of the vowel).
  113.      */
  114.  
  115. STATIC APTR
  116. FindIndexKey(UBYTE Hi,UBYTE Offset,UBYTE *KeyTable,UBYTE *KeyTypes,APTR Index)
  117. {
  118.     UBYTE    *String;
  119.     SHORT     i,j;
  120.  
  121.     for(i = 0 ; i < Hi ; i++)
  122.     {
  123.             /* Examine only the dead key entries. */
  124.  
  125.         if(KeyTypes[i] & KCF_DEAD)
  126.         {
  127.             String = (UBYTE *)(((ULONG *)KeyTable)[i]);
  128.  
  129.                 /* Look for a dead-key index. */
  130.  
  131.             for(j = 0 ; j < CountPairs(KeyTypes[i]) ; j++)
  132.             {
  133.                     /* This comes close to real magic:
  134.                      *
  135.                      * if the corresponding InputEvent
  136.                      * is of type RAWKEY, the EventAddress
  137.                      * pointer contains the packed
  138.                      * codes and qualifiers of the
  139.                      * previous key(s). The v37 header
  140.                      * files reflect this, but alas,
  141.                      * some guys will want to recompile
  142.                      * this code using v34 (and below)
  143.                      * header files.
  144.                      */
  145.  
  146.                 if(String[2 * j] == DPF_DEAD && (String[2 * j + 1] & 0x1F) == ((ULONG)Index & BYTEMASK))
  147.                     return((APTR)(((ULONG)(Offset + i) << 24) | (ULONG)PackQualifiers(j) << 16));
  148.             }
  149.         }
  150.     }
  151.  
  152.     return(NULL);
  153. }
  154.  
  155.     /* ScanKeyMap():
  156.      *
  157.      *    Scan a given keymap for an ANSI key and try to generate
  158.      *    an InputEvent which will -- if processed -- create the
  159.      *    given character.
  160.      */
  161.  
  162. STATIC BYTE
  163. ScanKeyMap(UBYTE Hi,UBYTE Offset,UBYTE *KeyTable,UBYTE *KeyTypes,UBYTE AnsiKey,struct InputEvent *Event,BYTE Depth)
  164. {
  165.         /* A bunch of qualifiers associated with KeyMapType bits. */
  166.  
  167.     STATIC struct {
  168.         UBYTE    QualBits;
  169.         UWORD    Qualifiers[4];
  170.     } QualType[8] = {
  171.         KC_NOQUAL,        0,                    0,            0,            0,
  172.         KCF_SHIFT,        0,                    0,            IEQUALIFIER_LSHIFT,    0,
  173.         KCF_ALT,        0,                    0,            IEQUALIFIER_LALT,    0,
  174.         KCF_CONTROL,        0,                    0,            IEQUALIFIER_CONTROL,    0,
  175.         KCF_ALT|KCF_SHIFT,    IEQUALIFIER_LSHIFT|IEQUALIFIER_LALT,    IEQUALIFIER_LALT,    IEQUALIFIER_LSHIFT,    0,
  176.         KCF_CONTROL|KCF_ALT,    IEQUALIFIER_CONTROL|IEQUALIFIER_LALT,    IEQUALIFIER_CONTROL,    IEQUALIFIER_LALT,    0,
  177.         KCF_CONTROL|KCF_SHIFT,    IEQUALIFIER_CONTROL|IEQUALIFIER_LSHIFT,    IEQUALIFIER_CONTROL,    IEQUALIFIER_LSHIFT,    0,
  178.         KC_VANILLA,        IEQUALIFIER_LSHIFT|IEQUALIFIER_LALT,    IEQUALIFIER_LALT,    IEQUALIFIER_LSHIFT,    0
  179.     };
  180.  
  181.     BYTE    *String;
  182.     SHORT     i,j,k;
  183.  
  184.         /* Scan the whole area. */
  185.  
  186.     for(i = 0 ; i < Hi ; i++)
  187.     {
  188.             /* This looks like a dead key. */
  189.  
  190.         if(KeyTypes[i] & KCF_DEAD)
  191.         {
  192.             String = (BYTE *)(((ULONG *)KeyTable)[i]);
  193.  
  194.                 /* Check all table entries. */
  195.  
  196.             for(j = 0 ; j < CountPairs(KeyTypes[i]) ; j++)
  197.             {
  198.                 switch(String[2 * j])
  199.                 {
  200.                         /* A simple dead key. */
  201.  
  202.                     case 0:        if((UBYTE)String[2 * j + 1] == AnsiKey)
  203.                             {
  204.                                 Event -> ie_Qualifier    = PackQualifiers(j);
  205.                                 Event -> ie_Code    = Offset + i;
  206.  
  207.                                 return(TRUE);
  208.                             }
  209.  
  210.                             break;
  211.  
  212.                         /* A dead-key-modifiable key. */
  213.  
  214.                     case DPF_MOD:    for(k = 0 ; k < Depth ; k++)
  215.                             {
  216.                                 if((UBYTE)String[String[2 * j + 1] + k] == AnsiKey)
  217.                                 {
  218.                                     Event -> ie_Qualifier    = PackQualifiers(j);
  219.                                     Event -> ie_Code    = Offset + i;
  220.  
  221.                                     Event -> ie_EventAddress = (APTR)k;
  222.  
  223.                                     return(TRUE);
  224.                                 }
  225.                             }
  226.  
  227.                             break;
  228.  
  229.                     default:    break;
  230.                 }
  231.             }
  232.         }
  233.  
  234.             /* This looks like a string. */
  235.  
  236.         if(KeyTypes[i] & KCF_STRING)
  237.         {
  238.             String = (BYTE *)(((ULONG *)KeyTable)[i]);
  239.  
  240.                 /* Only single character strings are
  241.                  * accepted, check the `no qualifier'
  242.                  * entry first.
  243.                  */
  244.  
  245.             if(String[0] == 1)
  246.             {
  247.                 if((UBYTE)String[String[1]] == AnsiKey)
  248.                 {
  249.                         /* Try to find the approriate
  250.                          * qualifier.
  251.                          */
  252.  
  253.                     for(k = 0 ; k < 8 ; k++)
  254.                     {
  255.                         if(QualType[k] . QualBits == (KeyTypes[i] & KC_VANILLA))
  256.                         {
  257.                             Event -> ie_Qualifier    = QualType[k] . Qualifiers[j];
  258.                             Event -> ie_Code    = Offset + i;
  259.  
  260.                             return(TRUE);
  261.                         }
  262.                     }
  263.                 }
  264.             }
  265.  
  266.                 /* Are there any strings left which
  267.                  * require a qualifier key to be
  268.                  * pressed?
  269.                  */
  270.  
  271.             for(j = 0 ; j < 3 ; j++)
  272.             {
  273.                 if(KeyTypes[i] & (1 << j))
  274.                 {
  275.                     if(String[2 + (2 * j)] == 1)
  276.                     {
  277.                         if((UBYTE)String[String[3 + (2 * j)]] == AnsiKey)
  278.                         {
  279.                             for(k = 0 ; k < 8 ; k++)
  280.                             {
  281.                                 if(QualType[k] . QualBits == (KeyTypes[i] & KC_VANILLA))
  282.                                 {
  283.                                     Event -> ie_Qualifier    = QualType[k] . Qualifiers[j];
  284.                                     Event -> ie_Code    = Offset + i;
  285.  
  286.                                     return(TRUE);
  287.                                 }
  288.                             }
  289.                         }
  290.                     }
  291.                 }
  292.             }
  293.         }
  294.         else
  295.         {
  296.                 /* At last, something sensible, check
  297.                  * the remaining vanilla type keys.
  298.                  */
  299.  
  300.             for(j = 3 ; j >= 0 ; j--)
  301.             {
  302.                 if(AnsiKey == KeyTable[4 * i + j])
  303.                 {
  304.                     for(k = 0 ; k < 8 ; k++)
  305.                     {
  306.                         if(QualType[k] . QualBits == KeyTypes[i])
  307.                         {
  308.                             Event -> ie_Code = Offset + i;
  309.  
  310.                             if(QualType[k] . QualBits == KC_VANILLA)
  311.                             {
  312.                                 if(AnsiKey & 96)
  313.                                     Event -> ie_Qualifier = QualType[k] . Qualifiers[j];
  314.                                 else
  315.                                     Event -> ie_Qualifier = IEQUALIFIER_CONTROL;
  316.                             }
  317.                             else
  318.                                 Event -> ie_Qualifier = QualType[k] . Qualifiers[j];
  319.  
  320.                             return(TRUE);
  321.                         }
  322.                     }
  323.                 }
  324.             }
  325.         }
  326.     }
  327.  
  328.     return(FALSE);
  329. }
  330.  
  331.     /* InvertKeyMap():
  332.      *
  333.      *    Invert a given character.
  334.      */
  335.  
  336. BYTE
  337. KeyInvert(UBYTE AnsiKey,struct InputEvent *Event,struct KeyMap *KeyMap,BYTE Depth)
  338. {
  339.     BYTE Result;
  340.  
  341.     Event -> ie_Class        = IECLASS_RAWKEY;
  342.     Event -> ie_EventAddress    = NULL;
  343.  
  344.         /* Check the high keymap types first to include control keys
  345.          * such as backspace, return, delete, etc. instead of the
  346.          * control+? combination given in the low keymap entries.
  347.          */
  348.  
  349.     if(!(Result = ScanKeyMap(0x28,0x40,(UBYTE *)KeyMap -> km_HiKeyMap,(UBYTE *)KeyMap -> km_HiKeyMapTypes,AnsiKey & BYTEMASK,Event,Depth)))
  350.         Result = ScanKeyMap(0x40,0x00,(UBYTE *)KeyMap -> km_LoKeyMap,(UBYTE *)KeyMap -> km_LoKeyMapTypes,AnsiKey & BYTEMASK,Event,Depth);
  351.  
  352.         /* See if we are to generate a preceding keystroke. */
  353.  
  354.     if(Result && Event -> ie_EventAddress)
  355.     {
  356.         APTR Address;
  357.  
  358.             /* Find the preceding keystroke. */
  359.  
  360.         if(!(Address = FindIndexKey(0x28,0x40,(UBYTE *)KeyMap -> km_HiKeyMap,(UBYTE *)KeyMap -> km_HiKeyMapTypes,Event -> ie_EventAddress)))
  361.             Address = FindIndexKey(0x40,0x00,(UBYTE *)KeyMap -> km_LoKeyMap,(UBYTE *)KeyMap -> km_LoKeyMapTypes,Event -> ie_EventAddress);
  362.  
  363.             /* Heavy magic, don't touch! */
  364.  
  365.         if(!(Event -> ie_EventAddress = Address))
  366.             return(FALSE);
  367.     }
  368.  
  369.     return(Result);
  370. }
  371.